﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using umbraco.cms.businesslogic.web;
using umbraco.cms.businesslogic;

namespace TheOutfield.UmbExt.DocumentSorter
{
    public class ApplicationBase : umbraco.BusinessLogic.ApplicationBase
    {
        public ApplicationBase()
        {
            Document.AfterNew += new EventHandler<umbraco.cms.businesslogic.NewEventArgs>(Document_AfterNew);
            Document.AfterSave += new Document.SaveEventHandler(Document_Sort);
            Document.AfterPublish += new Document.PublishEventHandler(Document_Sort);
        }

        protected void Document_AfterNew(object sender, umbraco.cms.businesslogic.NewEventArgs e)
        {
            var doc = sender as Document;
            if (doc != null)
                Document_Sort(doc, e);
        }

        protected void Document_Sort(Document doc, object e)
        {
            var configEntries = new List<DocumentSorterConfigEntry>();

            if (DocumentSorterConfig.Instance.ConfigEntries.ContainsKey(doc.ContentType.Alias))
                configEntries.AddRange(DocumentSorterConfig.Instance.ConfigEntries[doc.ContentType.Alias]);

            if (DocumentSorterConfig.Instance.ConfigEntries.ContainsKey("$_ALL"))
                configEntries.AddRange(DocumentSorterConfig.Instance.ConfigEntries["$_ALL"]);

            if (configEntries.Count > 0)
            {
                if (doc.Level <= 1)
                    return;

                var parent = doc.Parent;
                if (parent == null)
                    return;

                var parentDoc = new Document(parent.Id);
                if (parentDoc == null)
                    return;

                foreach(var configEntry in configEntries)
                {
                    var isValid = true;
                    if (!String.IsNullOrEmpty(configEntry.RootXPath))
                    {
                        var ids = GetNodeIdsFromXpath(configEntry.RootXPath);
                        isValid = ids.Contains(parentDoc.Id);
                    }

                    if (!isValid)
                        continue;

                    var simpleDocs = new List<SimpleDocument>();
                    var currentSortOrder = "";

                    Document[] childDocs = parentDoc.Children;
                    foreach (var childDoc in childDocs)
                    {
                        var simpleDoc = new SimpleDocument();
                        simpleDoc.Id = childDoc.Id;

                        switch (configEntry.Field)
                        {
                            case "id":
                                simpleDoc.Field = childDoc.Id;
                                configEntry.Type = Type.Numeric;
                                break;
                            case "nodeName":
                                simpleDoc.Field = childDoc.Text;
                                configEntry.Type = Type.Alpha;
                                break;
                            case "createDate":
                                simpleDoc.Field = childDoc.CreateDateTime;
                                configEntry.Type = Type.Date;
                                break;
                            case "updateDate":
                                simpleDoc.Field = childDoc.UpdateDate;
                                configEntry.Type = Type.Date;
                                break;
                            default:
                                if (childDoc.ContentType.Alias == configEntry.DocTypeAlias || configEntry.DocTypeAlias == "$_ALL")
                                    simpleDoc.Field = childDoc.getProperty(configEntry.Field).Value;
                                else
                                    simpleDoc.Field = null;
                                break;
                        }

                        simpleDocs.Add(simpleDoc);

                        currentSortOrder += childDoc.Id + ",";
                    }

                    simpleDocs.Sort(CreateComparerFromType(configEntry.Type));

                    if (configEntry.Order == Order.Desc)
                        simpleDocs.Reverse();

                    var sortOrder = "";
                    foreach (var simpleDoc in simpleDocs)
                        sortOrder += simpleDoc.Id + ",";

                    if (sortOrder.Trim(',') != currentSortOrder.Trim(','))
                    {
                        var nodeSorter = new umbraco.presentation.webservices.nodeSorter();
                        nodeSorter.UpdateSortOrder(parentDoc.Id, sortOrder.Trim(','));

                        if (!configEntry.DisableTreeRefresh && HttpContext.Current != null)
                            umbraco.BasePages.BasePage.Current.ClientTools.SyncTree(doc.Parent.Path, true);
                    }
                }

            }
        }

        protected List<int> GetNodeIdsFromXpath(string xpath)
        {
            var ids = new List<int>();
            var nodes = umbraco.library.GetXmlNodeByXPath(xpath);
            while (nodes.MoveNext())
            {
                ids.Add(Convert.ToInt32(nodes.Current.GetAttribute("id", "")));
            }
            return ids;
        }

        protected IComparer<SimpleDocument> CreateComparerFromType(Type type)
        {
            switch (type)
            {
                case Type.Alpha:
                    return new AlphaComparer();
                case Type.Numeric:
                    return new NumericComparer();
                case Type.Date:
                    return new DateComparer();
                default:
                    throw new ArgumentException("Unsupported type: "+ type.ToString());
            }
        }
    }
}